﻿#include "EditableTextWidget.h"
#include "Framework/Application.h"
#include "Font/FontSubsystem.h"
#include "Platform/PlatformInterface.h"
#include "Widgets/Window.h"
#include "Render/Widget/RenderWidgets.h"

REditableTextWidget::REditableTextWidget()
{
    Mouse=NewWidget<RMouseWidget>(this);
    Mouse->Anchor.Fill(this);
    Mouse->CursorShape=EMouseCursorType::IBeam;

    Keyboard=NewWidget<RKeyboardWidget>(this);
    Keyboard->Anchor.Fill(this);
    Mouse->AutoFocusTarget=Keyboard;
    //Mouse->bAutoFocusConsumesEvent=false;
    Keyboard->OnKeyboardFocused.Bind(this,&REditableTextWidget::OnFocused);
    Keyboard->OnKeyboardUnfocused.Bind(this,&REditableTextWidget::OnUnfocused);
    Keyboard->OnTextInput.Bind(this,&REditableTextWidget::ProcessTextInput);
    Keyboard->OnKeyboardInput.Bind(this,&REditableTextWidget::ProcessKeyInput);

    RMouseWidgetWeakPtr MouseWeak=Mouse;
    Mouse->OnClicked.BindLambda([this,MouseWeak](const SMouseButtonEvent &)->bool
    {
        //计算光标位置
        auto MousePosition=this->GetMousePositionInWidget();
        CursorPosition= TextArranger.GetArrangeResult().CalculateCursorIndex(MousePosition);
        return true;
    }); 

}

CString REditableTextWidget::GetDisplayingText()
{
    if(bIsEditing)
    {
        return EditingDisplayText;
    }
    else
    {
        return Text.Get();
    }
}

void REditableTextWidget::StartEdit()
{
    Keyboard->Focus();
}

void REditableTextWidget::CancelEdit()
{
    if(bIsEditing)
    {
        bIsEditing=false;
        Keyboard->Unfocus();
        OnEditStopped.Broadcast(ETextEditStopReason::Cancel,EditingDisplayText);
    }
}

bool REditableTextWidget::IsEditing()
{
    return bIsEditing;
}

void REditableTextWidget::PaintSelf(uint16_t &InZOrder, const SRect &InClipArea)
{
    //paint text
    bool PaintText=TextArranger.GetArrangeResult().GetRenderCharCount()>0;
    if(PaintText)
    {
        auto RenderTextWidget=std::make_shared<SRenderStaticTextWidget>();
        RenderTextWidget->Rect=SRect(PresentAbsPosition,PresentSize);
        RenderTextWidget->ClipRect=InClipArea;
        RenderTextWidget->ZOrder=InZOrder;
        InZOrder++;

        RenderTextWidget->TextColor= Color.Get();
        RenderTextWidget->CharTextures=TextArranger.GetArrangeResult().GetRenderCharTextures();
        RenderTextWidget->CharPositions=TextArranger.GetArrangeResult().GetCharPositions();


        PaintRenderWidget(RenderTextWidget); 
    }

    //paint cursor
    bool PaintCursor=bIsEditing&&bShowCursor;
    if(PaintCursor)
    {
        auto Cursor=std::make_shared<SRenderRectWidget>();
        Cursor->bFill=true;
        Cursor->FillColor=CursorColor.Get();
        Cursor->ZOrder=InZOrder;
        Cursor->ClipRect=InClipArea;

        //计算光标矩形
        auto CursorRect=TextArranger.GetArrangeResult().CalculateCursorRect(CursorPosition,CursorWidth.Get());
        CursorRect.Min+=PresentAbsPosition;
        Cursor->Rect=CursorRect;
        PaintRenderWidget(Cursor);
    }

    if(PaintText||PaintCursor)
    {
        InZOrder++;
    }
}


void REditableTextWidget::CalculatePresentPositionAndSize()
{
    Super::CalculatePresentPositionAndSize();
    ArrangeGlyphs();

}

void REditableTextWidget::ArrangeGlyphs()
{
    STextArrangePapameters Params;
    Params.Font=GetRenderingFont();
    Params.FontSize=FontSize.Get();
    if(bIsEditing)
    {
        Params.Text=EditingDisplayText;
    }
    else
    {
        Params.Text=Text.Get();
    }
    Params.Wrap=ETextWrapMethod::None;
    Params.HorizontalAlign=HorizontalAlignment.Get();
    Params.VerticalAlign=VerticalAlignment.Get();
    Params.PaintAreaSize=PresentSize;

    TextArranger.ArrangeText(Params);
    
 
}

void REditableTextWidget::OnFocused()
{
    bIsEditing=true;
    EditingDisplayText=Text.Get();
    ForceShowCursor();

    IPlatformInterface::GetPlatformInterface()->StartTextInput(
        GetWindow()->GetWindowID()
        ,GetWindow()->ContentSpaceToWindowSpace(
            SIntPoint(
                PresentAbsPosition.X
                ,PresentAbsPosition.Y+PresentSize.Y
            )
        )
    );
}

void REditableTextWidget::OnUnfocused()
{
    if(bIsEditing)
    {
        bIsEditing=false;
        if(UpdateTextOnLostFocus.Get())
        {
            Text=EditingDisplayText;
        }
        OnEditStopped.Broadcast(ETextEditStopReason::LostFocus,EditingDisplayText);
    }
    HideCursor();

    IPlatformInterface::GetPlatformInterface()->StopTextInput();
}

bool REditableTextWidget::ProcessTextInput(const STextInputEvent &InEvent)
{
    assert(bIsEditing);

    CString InputText=InEvent.GetInputText();

    if(CursorPosition==EditingDisplayText.GetLength()-1)
    {
        //在末尾插入
        EditingDisplayText+=InputText;
    }
    else
    {
        EditingDisplayText=EditingDisplayText.Insert(CursorPosition+1,InputText);
    }
    OnTextUpdated.Broadcast(EditingDisplayText);

    CursorPosition+=InputText.GetLength();    
    ForceShowCursor();

    return true;
}

bool REditableTextWidget::ProcessKeyInput(const SKeyboardEvent &BoardkeyEvent)
{
    if(!bIsEditing)
    {
        return false;
    }

    if(BoardkeyEvent.KeyState!=EKeyState::Pressed)
    {
        return false;
    }

    switch(BoardkeyEvent.Key)
    {
        case EKey::Left:
        {
            if(CursorPosition>-1)
            {
                CursorPosition--;
            }
            ForceShowCursor();
            break;
        }

        case EKey::Right:
        {
            if(CursorPosition<EditingDisplayText.GetLength()-1)
            {
                CursorPosition++;
            }
            ForceShowCursor();
            break;
        }

        case EKey::Backspace:
        {
            if(CursorPosition>-1)
            {
                EditingDisplayText=EditingDisplayText.RemoveAt(CursorPosition,1);
                CursorPosition--;
                OnTextUpdated.Broadcast(EditingDisplayText);
            }
            ForceShowCursor();
            break;
        }

        case EKey::Enter:
        {
            bIsEditing=false;
            Keyboard->Unfocus();
            OnEditStopped.Broadcast(ETextEditStopReason::Accept,EditingDisplayText);
            if(UpdateTextOnAccepted.Get())
            {
                Text=EditingDisplayText;
            }
            OnTextAccepted.Broadcast(EditingDisplayText);
            break;
        }

        case EKey::Escape:
        {
            bIsEditing=false;
            Keyboard->Unfocus();
            OnEditStopped.Broadcast(ETextEditStopReason::Cancel,EditingDisplayText);
            break;
        }
    }

    return true;

}

void REditableTextWidget::ForceShowCursor()
{
    bShowCursor=true;
    CursorTime=0;
}

void REditableTextWidget::HideCursor()
{
    bShowCursor=false;
    CursorTime=0;
}

TSharedObjectPtr<RFont> REditableTextWidget::GetRenderingFont()
{
    if(Font.IsValid())
    {
        return Font.Get();
    }
    else
    {
        return RApplication::GetApplication()->GetSubsystem<RFontApplicationSubsystem>()->GetDefaultFont();
    }
}

void REditableTextWidget::Tick(float DeltaSeconds)
{
    if(bIsEditing)
    {
        CursorTime+=DeltaSeconds;
        if(CursorTime>CursorBlinkTime)
        {
            CursorTime-=CursorBlinkTime;
            bShowCursor=!bShowCursor;
        }
    }

    Super::Tick(DeltaSeconds);
}
